/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.tests;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import mosdi.util.BitArray;

public class BitArrayTest extends TestCase {

	public void test() {
		BitArray ba = new BitArray(200);
		assertEquals(200, ba.size());
		for (int i=0; i<200; ++i) assertFalse(ba.get(i));
		try { 
			ba.get(-1);
			fail();
		} catch (IndexOutOfBoundsException e) {}
		try { 
			ba.get(200);
			fail();
		} catch (IndexOutOfBoundsException e) {}
		try { 
			ba.set(-1, true);
			fail();
		} catch (IndexOutOfBoundsException e) {}
		try { 
			ba.set(200, true);
			fail();
		} catch (IndexOutOfBoundsException e) {}
		ba.set(0, true);
		ba.set(10, true);
		ba.set(20, true);
		ba.set(63, true);
		ba.set(128, true);
		ba.set(193, true);
		for (int i=0; i<200; ++i) {
			if ((i==0) || (i==10) || (i==20) || (i==63) || (i==128) || (i==193)) {
				assertTrue(String.format("Offending value: %d", i), ba.get(i));
				continue;  
			}
			assertFalse(String.format("Offending value: %d", i), ba.get(i));
		}
	}

	public void testIterator() {
		BitArray ba = new BitArray(200);
		ba.set(0, true);
		ba.set(4, true);
		ba.set(7, true);
		ba.set(63, true);
		ba.set(65, true);
		int n=0;
		for (boolean b : ba) {
			if ((n==0)||(n==4)||(n==7)||(n==63)||(n==65)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		assertEquals(200,n);
	}

	public void testShift1() {
		BitArray ba = new BitArray(200);
		ba.set(0, true);
		ba.set(4, true);
		ba.set(7, true);
		ba.set(62, true);
		ba.set(63, true);
		ba.set(65, true);
		ba.shiftLeft();
		int n=0;
		for (boolean b : ba) {
			if ((n==1)||(n==5)||(n==8)||(n==63)||(n==64)||(n==66)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		n=0;
		ba.shiftLeft();
		for (boolean b : ba) {
			if ((n==2)||(n==6)||(n==9)||(n==64)||(n==65)||(n==67)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		ba.shiftRight();
		n=0;
		for (boolean b : ba) {
			if ((n==1)||(n==5)||(n==8)||(n==63)||(n==64)||(n==66)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		ba.shiftRight();
		n=0;
		for (boolean b : ba) {
			if ((n==0)||(n==4)||(n==7)||(n==62)||(n==63)||(n==65)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		ba.shiftRight();
		n=0;
		for (boolean b : ba) {
			if ((n==3)||(n==6)||(n==61)||(n==62)||(n==64)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
	}

	public void testShift2() {
		BitArray ba1 = new BitArray(200);
		ba1.set(198, true);
		ba1.set(199, true);
		ba1.shiftLeft();
		BitArray ba2 = new BitArray(200);
		ba2.set(199, true);
		assertTrue(ba1.compareTo(ba2)==0);
	}

	public void testShift3() {
		BitArray ba = new BitArray(36);
		ba.set(0, true);
		ba.set(2, true);
		ba.set(3, true);
		ba.shiftLeft();
		int n=0;
		for (boolean b : ba) {
			if ((n==1)||(n==3)||(n==4)) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
	}

	public void testShift4() {
		BitArray ba = new BitArray(64);
		ba.set(0, true);
		ba.shiftLeft();
		int n=0;
		for (boolean b : ba) {
			if (n==1) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
	}

	public void testAndOr() {
		BitArray ba1 = new BitArray(64);
		BitArray ba2 = new BitArray(64);
		BitArray ba3 = new BitArray(64);
		ba1.set(63, true);
		ba2.set(63, true);
		ba1.and(ba2);
		int n=0;
		for (boolean b : ba1) {
			if (n==63) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
		ba1.and(ba3);
		for (boolean b : ba1) assertFalse(String.format("Offending value: %d", n),b);
		ba1.or(ba2);
		n=0;
		for (boolean b : ba1) {
			if (n==63) assertTrue(String.format("Offending value: %d", n),b);
			else assertFalse(String.format("Offending value: %d", n),b);
			++n;
		}
	}

	public void testNumberOfOnes() {
		BitArray ba = new BitArray(65);
		ba.set(64, true);
		ba.set(63, true);
		ba.set(62, true);
		ba.set(30, true);
		ba.set(1, true);
		ba.set(0, true);
		assertEquals(6, ba.numberOfOnes());
	}

	public void testSubset() {
		BitArray ba1 = new BitArray(70);
		ba1.set(64, true);
		ba1.set(62, true);
		ba1.set(30, true);
		ba1.set(1, true);
		ba1.set(0, true);
		BitArray ba2 = new BitArray(70);
		assertTrue(ba2.subsetOf(ba1));
		ba2.set(1, true);
		assertTrue(ba2.subsetOf(ba1));
		ba2.set(64, true);
		assertTrue(ba2.subsetOf(ba1));
		ba2.set(62, true);
		assertTrue(ba2.subsetOf(ba1));
		ba2.set(63, true);
		assertFalse(ba2.subsetOf(ba1));
	}

	public void testToString() {
		BitArray ba = new BitArray(70);
		ba.set(0, true);
		ba.set(4, true);
		ba.set(7, true);
		ba.set(62, true);
		ba.set(63, true);
		ba.set(65, true);
		assertEquals("(0000101100000000000000000000000000000000000000000000000000000010010001)", ba.toString());
	}

	public void testStringConstructor() {
		String s = "110011011110110011000101010100101101001100101010000110011110000000010111111000001010100010011111011011101011010010110011111010110011010001111010111011";
		BitArray ba = new BitArray(s);
		assertEquals("("+s+")", ba.toString());
	}

	public void testSubarray() {
		String s = "110011011110110011000101010100101101001100101010000110011110000000010111111000001010100010011111011011101011010010110011111010110011010001111010111011";
		BitArray ba = new BitArray(s);
		assertEquals("(1010111011)", ba.copyOfSubarray(0,10).toString());
		assertEquals("(0010011111011011101011010010110011111010110011010001111010111011)", ba.copyOfSubarray(0,64).toString());
		assertEquals("(00010011111011011101011010010110011111010110011010001111010111011)", ba.copyOfSubarray(0,65).toString());
		assertEquals("(100010011111011011101011010010110011111010110011010001111010111011)", ba.copyOfSubarray(0,66).toString());
		assertEquals("(000100111110110111010110100101100111110101100110100011110101)", ba.copyOfSubarray(5,65).toString());
		assertEquals("(1000100111110110111010110100101100111110101100110100011110101)", ba.copyOfSubarray(5,66).toString());
		assertEquals("(100)", ba.copyOfSubarray(63,66).toString());
		assertEquals("(000001010100)", ba.copyOfSubarray(63,75).toString());
		assertEquals("(00000101010)", ba.copyOfSubarray(64,75).toString());
		assertEquals("(01010100101101001100101010000110011110000000010111111000001010100010)", ba.copyOfSubarray(60,128).toString());
		assertEquals("(101010100101101001100101010000110011110000000010111111000001010100010)", ba.copyOfSubarray(60,129).toString());
		assertEquals("(0101010100101101001100101010000110011110000000010111111000001010100010)", ba.copyOfSubarray(60,130).toString());
		assertEquals("(11001101111011001100010101010010110100110010101000)", ba.copyOfSubarray(100,150).toString());
	}

	public void testJoin() {
		BitArray all = new BitArray("10010001010000000100000101110101000111100010110010101001110110001001101101010100110001101101010001000100010001100010111001010011101111110011011001111001101011101111110101001001110110100001110011110100100000001111110000101101110010010010000001000111011011001000111011101010101001001100110011110000011100101000111000101001100111010101001011010110010001001010101001101000110110001010110000011011000000100111101110010001011101110110100011110100100110100010101000000111000001100100110101010011000100011110");
		List<BitArray> list = new ArrayList<BitArray>();
		list.add(all.copyOfSubarray(0, 27));
		list.add(all.copyOfSubarray(27, 47));
		list.add(all.copyOfSubarray(47, 200));
		list.add(all.copyOfSubarray(200, 256));
		list.add(all.copyOfSubarray(256, 319));
		list.add(all.copyOfSubarray(319, 321));
		list.add(all.copyOfSubarray(321, 385));
		list.add(all.copyOfSubarray(385, 500));
		BitArray result = BitArray.join(list);
		assertTrue(all.equals(result));
	}
}
